/**
 * Project hdmap
 * @author shengjialiang
 * @version v1.0
 */


#ifndef _MINELAYER_H
#define _MINELAYER_H

#include "map_minedatarender/MineDataRenderConfig.h"
#include "map_datarender/SceneLayer.h"
#include "map_datarender/GeneralRenderObject.h"
#include "osg/ClipNode"
#include "osg/Group"

namespace Mine
{
	class CRenderUtil
	{
	public:
		static osg::ref_ptr<osg::Image> getImage(const std::string& image);
		static void calcuteIndex(osg::DrawElementsUInt* elements, uint32_t rows, uint32_t columns, bool ccw = true);
		static osg::Vec3Array* calcuteNormals(osg::Vec3Array* pts, osg::DrawElementsUInt* elements,bool ccw = true);
		static osg::ref_ptr<osg::Program> getOrCreateClipProgram();
	};

	enum class MAP_MINEDATARENDER_EXPORT ShowStyle
	{
		COLOR,
		TEXTURE
	};

	class MAP_MINEDATARENDER_EXPORT CMineRenderObject
		: public DataRender::CRenderObject
	{
	public:
		CMineRenderObject(osg::ref_ptr<osg::Group> in_pParentNode);

		virtual ~CMineRenderObject();

		virtual bool load();
	public:
		virtual bool clip(const osg::Plane& plane) { return true; }
		virtual bool clip(const osg::Vec3& startPt,const osg::Vec3& endPt) { return true; }
		virtual bool clip(const std::vector<osg::Vec3>& pts){ return true; };
		virtual bool clearClip(){ return true; }
		virtual void setShowStyle(ShowStyle style){}

	protected:
		virtual osg::ref_ptr<osg::Node> createNode()=0;

		virtual osg::ref_ptr<osg::Node> createNode(
			osg::ref_ptr<osg::Vec3dArray>& in_points, 
			osg::ref_ptr<osg::Vec4Array>& in_colors,
			osg::ref_ptr<osg::Vec3dArray>& in_normals,
			osg::ref_ptr<osg::Vec2dArray>& in_uvs,
			osg::ref_ptr<osg::Texture>& in_texture,
			std::vector<int>& in_indexes
			);
		
		virtual osg::ref_ptr<osg::Node> createNode(osg::ref_ptr<osg::Vec3dArray>& in_points, osg::ref_ptr<osg::Vec4Array>& in_colors)
		{
			return NULL;
		}

		virtual bool getData(osg::ref_ptr<osg::Vec3dArray>& inou_points, osg::ref_ptr<osg::Vec4Array>& inout_colors) { return false; }
	};

	class MAP_MINEDATARENDER_EXPORT CDrillRenderObject
		: public CMineRenderObject
	{
	public:
		CDrillRenderObject(osg::ref_ptr<osg::Group> in_pParentNode);
		~CDrillRenderObject();

	public:
		virtual void setShowStyle(ShowStyle style) override;

	protected:
		virtual osg::ref_ptr<osg::Node> createNode() override;
		virtual void onUnload() override;

	private:
		void createUnitCirclePts(float radius, std::vector<osg::Vec3>& pts);

	private:
		std::vector<osg::Geometry*> mGeometrys;
	};

	class MAP_MINEDATARENDER_EXPORT CStratumRenderObject
		: public CMineRenderObject
	{
	public:
		CStratumRenderObject(osg::ref_ptr<osg::Group> in_pParentNode);;
		~CStratumRenderObject(){};

	public:
		virtual bool clip(const osg::Plane& plane) override;
		virtual bool clip(const osg::Vec3& startPt, const osg::Vec3& endPt) override;
		virtual bool clip(const std::vector<osg::Vec3>& pts) override;
		virtual bool clearClip() override;
		virtual void setShowStyle(ShowStyle style);

	protected:
		virtual osg::ref_ptr<osg::Node> createNode() override;
		virtual void onUnload() override;

	private:
		std::vector<osg::Vec3> addPoints(const std::vector<osg::Vec3>& line, float gap);
		osg::Vec3 interpolationIDW(const osg::Vec3& pos, std::vector<osg::Vec3> samples);

		// line p1-p2  cross segment q1-q2
		bool crossPoint(const osg::Vec2& p1, const osg::Vec2& p2, const osg::Vec2& q1,
			const osg::Vec2& q2, osg::Vec2& crossPoint);

		bool ptInPolygon(const osg::Vec3& pt, const std::vector<osg::Vec3>& area);
	private:
		osg::Group* mNode = nullptr;
		osg::ClipNode* mClipNode = nullptr;
		
		osg::Geode* mTopGeodeNode = nullptr;
		osg::Geode* mSideGeodeNode = nullptr;
		osg::Geode* mBottomGeodeNode = nullptr;

		osg::Geode* mClipFaceGeoNode = nullptr;
		std::vector<osg::Geometry*> mGeometrys;
		std::vector<osg::Vec4> mGeometrysColors;

		std::vector<osg::Geometry*> mClipGeometrys;
		std::vector<osg::Vec4> mClipGeometrysColors;

		std::vector<osg::Vec3> mOutLines;

		bool mIsClip = false;
		osg::Plane mClipPlane;
		osg::Vec3 mClipStartPt;
		osg::Vec3 mClipEndPt;
	};

	class MAP_MINEDATARENDER_EXPORT CCoalRenderObject
		: public CMineRenderObject
	{
	public:
		CCoalRenderObject(osg::ref_ptr<osg::Group> in_pParentNode);;
		~CCoalRenderObject(){};

	public:
		virtual void setShowStyle(ShowStyle style) override;

	protected:
		virtual osg::ref_ptr<osg::Node> createNode() override;
		virtual void onUnload() override;

	private:
		osg::Geometry* mGeometry = nullptr;
	};

	class MAP_MINEDATARENDER_EXPORT CStratumSectionRenderObject
		: public CMineRenderObject
	{
	public:
		CStratumSectionRenderObject(osg::ref_ptr<osg::Group> in_pParentNode);
		~CStratumSectionRenderObject();

	protected:
		virtual osg::ref_ptr<osg::Node> createNode() override;
	};

	class MAP_MINEDATARENDER_EXPORT CMineLayer
		: public DataRender::CSceneLayer
	{
	public:
		CMineLayer(){};
		virtual ~CMineLayer(){};

	public:
		virtual bool clip(const osg::Plane& plane);
		virtual bool clip(const osg::Vec3& strtPt,const osg::Vec3& endPt);
		virtual bool clip(const std::vector<osg::Vec3>& pts);
		virtual bool clearClip();
		virtual void setShowStyle(ShowStyle style);
		ShowStyle getShowStyle() const { return mStyle; }

	protected:
		ShowStyle mStyle = ShowStyle::COLOR;
	};

	class MAP_MINEDATARENDER_EXPORT CDrillLayer 
		: public CMineLayer
    {
    public:
		CDrillLayer(){ mStyle = ShowStyle::COLOR; }
		~CDrillLayer(){};
    protected:
		virtual DataRender::IRenderObject* createRenderObject(DataManager::IFeature* in_pFeature, 
			osg::ref_ptr<osg::Group> in_pParentNode);

    };

	class MAP_MINEDATARENDER_EXPORT CStratumLayer
		: public CMineLayer
	{
	public:
		CStratumLayer(){};
		~CStratumLayer(){};

	protected:
		virtual DataRender::IRenderObject* createRenderObject(DataManager::IFeature* in_pFeature, 
			osg::ref_ptr<osg::Group> in_pParentNode) override;
	};

	class MAP_MINEDATARENDER_EXPORT CCoalLayer
		: public CMineLayer
	{
	public:
		CCoalLayer(){};
		~CCoalLayer(){};
	protected:
		virtual DataRender::IRenderObject* createRenderObject(DataManager::IFeature* in_pFeature, 
			osg::ref_ptr<osg::Group> in_pParentNode) override;
	};

}
#endif //_MINELAYER_H